package com.tuanzi.loan.log.repository.impl;

import static com.tuanzi.loan.generated.jooq.loan.tables.Log4j.LOG4J;

import java.util.ArrayList;
import java.util.List;

import org.jooq.Record;
import org.jooq.RecordMapper;
import org.jooq.UpdateConditionStep;
import org.jooq.impl.DSL;
import org.jooq.impl.TableImpl;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Repository;

import com.tuanzi.loan.core.repository.JOOQBaseRepositoryPlus;
import com.tuanzi.loan.generated.jooq.loan.tables.records.Log4jRecord;
import com.tuanzi.loan.log.entity.ErrorLogStatus;
import com.tuanzi.loan.log.repository.ErrorLogRepository;
import com.tuanzi.loan.log.vo.request.ErrorLogSearchRequest;
import com.tuanzi.loan.log.vo.response.ErrorLogDetailResponse;
import com.tuanzi.loan.log.vo.response.ErrorLogSearchResponse;

/**
 * @author JinRuiyang 2017/11/27
 */
@Repository
public class ErrorLogRepositoryImpl extends JOOQBaseRepositoryPlus implements ErrorLogRepository {

    public ErrorLogRepositoryImpl(){}

    /**
     * 根据id获取错误日志
     *
     * @param id id
     * @return 错误日志
     */
    @Override
    public ErrorLogDetailResponse findById(Long id) {
        return dslContext
                .select(LOG4J.fields())
                .from(getTable())
                .where(LOG4J.ID.eq(id))
                .fetchOne(new ErrorLogDetailResponseRecordMapper());
    }

    /**
     * 根据异常日志查询请求获取日志列表
     *
     * @param searchRequest 日志查询请求
     * @param pageable 分页
     * @return 异常日志列表
     */
    @Override
    public Page<ErrorLogSearchResponse> list(ErrorLogSearchRequest searchRequest, Pageable pageable) {
        fields(LOG4J.ID, LOG4J.FIRSTSTACK,LOG4J.PROJECTNAME,
                DSL.field("DATE_FORMAT(`log4j`.`createdate`,'%Y-%m-%d')").as("createTime"),
                DSL.count(LOG4J.ID).as("countNum"));
        contains(LOG4J.PROJECTNAME,searchRequest.getProjectName());
        eq(LOG4J.STATUS,ErrorLogStatus.UNCHECKED.getValue());
        ge(LOG4J.CREATEDATE,searchRequest.getStartTime());
        le(LOG4J.CREATEDATE,searchRequest.getEndTime());
        groupBy(LOG4J.PROJECTNAME);
        groupBy(LOG4J.FIRSTSTACK);
        orderBy(DSL.field("createTime"), Sort.Direction.DESC);
        orderBy(DSL.field("countNum"), Sort.Direction.DESC);
        return search(pageable, new ErrorLogSearchResponseRecordMapper());
    }

    /**
     * 获取异常日志表中的项目名称列表
     *
     * @return 项目名称列表
     */
    @Override
    public List<String> getProjectName() {
        return dslContext
                .selectDistinct(LOG4J.PROJECTNAME)
                .from(LOG4J)
                .fetch(LOG4J.PROJECTNAME);
    }

    /**
     * 批量更新异常日志的状态码
     *
     * @param exceptions 异常名称集合
     * @param status     需要更改为的状态码
     * @return 修改行数
     */
    @Override
    public int[] setStatus(List<ErrorLogSearchResponse> exceptions, Integer status) {
        List<UpdateConditionStep> updates = new ArrayList<>();
        for (ErrorLogSearchResponse exception : exceptions){
            updates.add(getStatusUpdateCondition(exception,status));
        }
        return dslContext.batch(updates).execute();
    }

    /**
     * 更新异常日志的状态码
     *
     * @param exception  异常名称
     * @param status     需要更改为的状态码
     * @return 修改行数
     */
    public int setStatus(ErrorLogSearchResponse exception, Integer status) {
        return getStatusUpdateCondition(exception,status).execute();
    }

    /**
     * 获取更新状态的更新语句
     * @param exception  异常名称
     * @param status     需要更改为的状态码
     * @return 更新语句
     */
    private UpdateConditionStep<Log4jRecord> getStatusUpdateCondition(ErrorLogSearchResponse exception, Integer status){
        if (exception == null)
            throw new NullPointerException("method arg:exceptions is null");
        if (exception.getProjectName() == null || exception.getFirstStack() == null)
            throw new NullPointerException("method arg:exception is invalid");
        return dslContext
                .update(LOG4J)
                .set(LOG4J.STATUS, status)
                .where(LOG4J.PROJECTNAME.eq(exception.getProjectName()))
                .and(LOG4J.FIRSTSTACK.eq(exception.getFirstStack()))
                .and(LOG4J.STATUS.eq(ErrorLogStatus.UNCHECKED.getValue()));
    }

    @Override
    protected TableImpl getTable() {
        return LOG4J;
    }

    private final class ErrorLogDetailResponseRecordMapper implements RecordMapper<Record, ErrorLogDetailResponse> {
        @Override
        public ErrorLogDetailResponse map(Record record) {
            ErrorLogDetailResponse response = new ErrorLogDetailResponse();
            response.setLogId(record.get(LOG4J.ID));
            response.setCreateTime(record.get(LOG4J.CREATEDATE));
            response.setFirstStack(record.get(LOG4J.FIRSTSTACK));
            response.setProjectName(record.get(LOG4J.PROJECTNAME));

            response.setException(record.get(LOG4J.EXCEPTION));
            response.setIp(record.get(LOG4J.IP));
            response.setMsg(record.get(LOG4J.MSG));
            response.setStackTrack(record.get(LOG4J.STACKTRACE));
            response.setStatus(record.get(LOG4J.STATUS));
            return response;
        }
    }

    private final class ErrorLogSearchResponseRecordMapper implements RecordMapper<Record, ErrorLogSearchResponse> {
        @Override
        public ErrorLogSearchResponse map(Record record) {
            ErrorLogSearchResponse response = new ErrorLogSearchResponse();
            response.setLogId(record.get(LOG4J.ID));
            response.setCount((Integer)record.get("countNum"));
            response.setCreateTimeStr((String)record.get("createTime"));
            response.setFirstStack(record.get(LOG4J.FIRSTSTACK));
            response.setProjectName(record.get(LOG4J.PROJECTNAME));
            return response;
        }
    }
}
